/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package xenon3d.vector;

/**
 * A 4 element point that is represented by single precision floating point x,y,z,w
 * coordinates.
 * @author Volker Everts
 * @version 0.1 - 19.08.2011: Created
 */
public class Point4f extends Tuple4f {

    // <editor-fold defaultstate="collapsed" desc=" Static Attributes ">

    /** The serial version UID. */
    private static final long serialVersionUID = 20110917L;

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Initialization ">

    /**
     * Constructs and initializes a Point4f to (0,0,0,0).
     */
    public Point4f() {
        super();
    }

    /**
     * Constructs and initializes a Point4f from the specified x, y, z and w
     * coordinates.
     * @param x the x coordinate
     * @param y the y coordinate
     * @param z the z coordinate
     * @param w the w coordinate
     */
    public Point4f(float x, float y, float z, float w) {
        super(x, y, z, w);
    }

    /**
     * Constructs and initializes a Point4f from the specified other tuple,
     * point or vector.
     * @param t the other tuple
     */
    public Point4f(Tuple4f t) {
        super(t);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Public Methods ">

    /**
     * Linearly interpolates between this point and another point p using the
     * interpolation factor d and places the result into this point:
     * this = (1 - d) * this + d * p.
     * @param p
     * @param d the interpolation factor, must be in the range 0 <= d <= 1
     */
    public final void interpolate(Point4f p, float d) {
        x = (1.0f - d) * x + d * p.x;
        y = (1.0f - d) * y + d * p.y;
        z = (1.0f - d) * z + d * p.z;
        w = (1.0f - d) * w + d * p.w;
    }

    /**
     * Linearly interpolates between two points p1 and p2 using the
     * interpolation factor d and places the result into this point:
     * this = (1 - d) * this + d * p.
     * @param p1 the first point
     * @param p2 the second point
     * @param d the interpolation factor, must be in the range 0 <= d <= 1
     */
    public final void interpolate(Point4f p1, Point4f p2, float d) {
        x = (1.0f - d) * p1.x + d * p2.x;
        y = (1.0f - d) * p1.y + d * p2.y;
        z = (1.0f - d) * p1.z + d * p2.z;
        w = (1.0f - d) * p1.w + d * p2.w;
    }

    /**
     * Multiplies each of the x, y, z components of the Point4f parameter by
     * 1/w and places the projected values into this point. The w value of this
     * point is set to 1.
     * @param p the point to project
     */
    public final void project(Point4f p) {
        float w1 = 1.0f / p.w;
        x = p.x * w1;
        y = p.y * w1;
        z = p.z * w1;
        w = 1.0f;
    }

    /**
     * Returns the distance between this point and another point p, given by its
     * x,y,z,w coordinates.
     * @param x the other point's x coordinate
     * @param y the other point's y coordinate
     * @param z the other point's z coordinate
     * @param w the other point's w coordinate
     * @return the distance
     */
    public float distance(float x, float y, float z, float w) {
        return FMath.sqrt(distanceSq(x, y, z, w));
    }

    /**
     * Returns the distance between this point and another point p.
     * @param p the other point
     * @return the distance
     */
    public float distance(Point4f p) {
        return FMath.sqrt(distanceSq(p));
    }

    /**
     * Returns the squared distance between this point and another point p,
     * given by its x,y,z,w coordinates.<p>
     * NOTE: This method is much faster than using <code>distance()</code>.
     * @param x the other point's x coordinate
     * @param y the other point's y coordinate
     * @param z the other point's z coordinate
     * @param w the other point's w coordinate
     * @return the squared distance
     */
    public float distanceSq(float x, float y, float z, float w) {
        return (this.x - x) * (this.x - x) + (this.y - y) * (this.y - y) + (this.z - z) * (this.z - z) + (this.w - w) * (this.w - w);
    }

    /**
     * Returns the squared distance between this point and another point p.<p>
     * NOTE: This method is much faster than using <code>distance()</code>.
     * @param p the other point
     * @return the squared distance
     */
    public float distanceSq(Point4f p) {
        return (x - p.x) * (x - p.x) + (y - p.y) * (y - p.y) + (z - p.z) * (z - p.z) + (w - p.w) * (w - p.w);
    }

    /**
     * Returns the L-1 (Manhattan) distance between this point and another point
     * p, given by its x,y,z,w coordinates. The L-1 distance is equal to
     * abs(x1-x2) + abs(y1-y2) + abs(z1-z2) + abs(w1-w2).
     * @param x the other point's x coordinate
     * @param y the other point's y coordinate
     * @param z the other point's z coordinate
     * @param w the other point's w coordinate
     * @return the L-1 distance
     */
    public float distanceL1(float x, float y, float z, float w) {
        return FMath.abs(this.x - x) + FMath.abs(this.y - y) + FMath.abs(this.z - z) + FMath.abs(this.w - w);
    }

    /**
     * Returns the L-1 (Manhattan) distance between this point and another point p.
     * The L-1 distance is equal to abs(x1-x2) + abs(y1-y2) + abs(z1-z2) +
     * abs(w1-w2).
     * @param p the other point
     * @return the L-1 distance
     */
    public float distanceL1(Point4f p) {
        return FMath.abs(x - p.x) + FMath.abs(y - p.y) + FMath.abs(z - p.z) + FMath.abs(w - p.w);
    }

    /**
     * Returns the L-infinite distance between this point and another point p,
     * given by its x,y,z,w coordinates.
     * The L-infinite distance is equal to MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2),
     * abs(w1-w2)].
     * @param x the other point's x coordinate
     * @param y the other point's y coordinate
     * @param z the other point's z coordinate
     * @param w the other point's w coordinate
     * @return the L-infinite distance
     */
    public float distanceLinf(float x, float y, float z, float w) {
        return FMath.max(FMath.abs(this.x - x), FMath.abs(this.y - y), FMath.abs(this.z - z), FMath.abs(this.w - w));
    }

    /**
     * Returns the L-infinite distance between this point and another point p.
     * The L-infinite distance is equal to MAX[abs(x1-x2), abs(y1-y2),
     * abs(z1 - z2), abs(w1-w2)].
     * @param p the other point
     * @return the L-infinite distance
     */
    public float distanceLinf(Point4f p) {
        return FMath.max(FMath.abs(x - p.x), FMath.abs(y - p.y), FMath.abs(z - p.z), FMath.abs(w - p.w));
    }

    // </editor-fold>

} // end class Point4f